package trie

import (
	"net/http"
	"strings"
)

type router struct {
	roots    map[string]*node       // verb trie  {verb: *node}  路径管理，类似于检索
	handlers map[string]HandlerFunc // 路径-> 实际处理器映射，相当于仓库
}

func newRouter() *router {
	return &router{
		roots:    make(map[string]*node),
		handlers: make(map[string]HandlerFunc),
	}
}

// handle 处理路由调用
func (r *router) handle(c *Context) {
	// 使用访问的path换取，节点对象
	n, params := r.getRoute(c.Method, c.Path)
	if n != nil {
		// 延迟赋值上下方中的路径参数
		c.Params = params
		key := c.Method + "-" + n.pattern // 此处存储的用的是节点pattern而非访问的path
		r.handlers[key](c)                // 调用实际处理逻辑
	} else {
		c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)
	}
}

// 通过进来的路径 获取 节点树上可能存在的动态参数值
func (r *router) getRoute(method string, path string) (*node, map[string]string) {
	searchParts := parsePattern(path)
	params := make(map[string]string)
	root, ok := r.roots[method]

	if !ok {
		return nil, nil
	}

	n := root.search(searchParts, 0) // 得到节点对象
	if n != nil {
		parts := parsePattern(n.pattern)
		for index, part := range parts {
			if part[0] == ':' {
				params[part[1:]] = searchParts[index] //获取具名参数名及对应的part, 基于位置的一对映射
			}
			if part[0] == '*' && len(part) > 1 { //静态资源访问路径处理
				params[part[1:]] = strings.Join(searchParts[index:], "/") //向后子全路径
				break
			}
		}
		return n, params // 获取路由节点及当前节点
	}
	return nil, nil
}

// Only one * is allowed
// extract node value
func parsePattern(path string) []string {
	vs := strings.Split(path, "/")

	parts := make([]string, 0)
	for _, item := range vs {
		if item != "" {
			parts = append(parts, item)
			if item[0] == '*' {
				break
			}
		}
	}
	return parts
}

// 路由值绑定
// 延迟绑定节点,处理函数
func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {
	parts := parsePattern(pattern)

	key := method + "-" + pattern
	_, ok := r.roots[method]
	if !ok {
		r.roots[method] = &node{}
	}
	r.roots[method].insert(pattern, parts, 0)
	r.handlers[key] = handler
}

// 获取指定的verb 路由树
func (r *router) getRoutes(method string) []*node {
	root, ok := r.roots[method]
	if !ok {
		return nil
	}
	nodes := make([]*node, 0)
	root.travel(&nodes)
	return nodes
}
